<!DOCTYPE html>
<html lang='zh-CN'>

<head>
  <meta name="generator" content="Hexo 6.3.0">
  <meta name="hexo-theme" content="https://github.com/xaoxuu/hexo-theme-stellar/tree/1.19.0">
  <meta charset="utf-8">
  

  <meta http-equiv='x-dns-prefetch-control' content='on' />
  <link rel='dns-prefetch' href='https://gcore.jsdelivr.net'>
  <link rel="preconnect" href="https://gcore.jsdelivr.net" crossorigin>
  <link rel='dns-prefetch' href='//unpkg.com'>

  <meta name="renderer" content="webkit">
  <meta name="force-rendering" content="webkit">
  <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
  <meta name="HandheldFriendly" content="True" >
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="theme-color" content="#f8f8f8">
  
  <title>设计模式摘录 - 愔颂</title>

  
    <meta name="description" content="《深入设计模式》一书阅读摘录。">
<meta property="og:type" content="article">
<meta property="og:title" content="设计模式摘录">
<meta property="og:url" content="https://farhills.gitee.io/2023/10/05/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E6%91%98%E5%BD%95/index.html">
<meta property="og:site_name" content="愔颂">
<meta property="og:description" content="《深入设计模式》一书阅读摘录。">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="https://refactoringguru.cn/images/patterns/diagrams/factory-method/solution2-zh.png">
<meta property="og:image" content="https://refactoringguru.cn/images/patterns/diagrams/abstract-factory/solution2.png">
<meta property="og:image" content="https://refactoringguru.cn/images/patterns/diagrams/builder/problem1.png">
<meta property="og:image" content="https://refactoringguru.cn/images/patterns/diagrams/builder/solution1.png">
<meta property="og:image" content="https://refactoringguru.cn/images/patterns/content/prototype/prototype-comic-3-zh.png">
<meta property="og:image" content="https://cdn.nlark.com/yuque/0/2023/png/36098302/1696572347922-e9a975ca-d125-4c53-a69a-60edb730acd4.png?x-oss-process=image%2Fresize%2Cw_1248%2Climit_0">
<meta property="og:image" content="https://refactoringguru.cn/images/patterns/content/observer/observer-comic-2-zh.png">
<meta property="og:image" content="https://refactoringguru.cn/images/patterns/content/strategy/strategy-comic-1-zh.png">
<meta property="og:image" content="https://refactoringguru.cn/images/patterns/diagrams/template-method/live-example.png">
<meta property="og:image" content="https://cdn.nlark.com/yuque/0/2023/png/36098302/1696508054996-bb868776-e528-402a-b19e-793a9b6f2190.png?x-oss-process=image%2Fresize%2Cw_1248%2Climit_0">
<meta property="article:published_time" content="2023-10-05T12:49:24.027Z">
<meta property="article:modified_time" content="2023-10-26T01:11:36.306Z">
<meta property="article:author" content="远岫">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="https://refactoringguru.cn/images/patterns/diagrams/factory-method/solution2-zh.png">
  
  
  
  

  <!-- feed -->
  

  
    
<link rel="stylesheet" href="/css/main.css">

  

  
    <link rel="shortcut icon" href="https://z1.ax1x.com/2023/10/05/pPXijyT.png">
  

  

  


  
</head>

<body>
  




  <div class='l_body' id='start'>
    <aside class='l_left' layout='post'>
    

  

<header class="header"><div class="logo-wrap"><a class="avatar" href="/about/"><div class="bg" style="opacity:0;background-image:url(https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/avatar/round/rainbow64@3x.webp);"></div><img no-lazy class="avatar" src="https://s1.ax1x.com/2022/11/12/ziJjfK.jpg" onerror="javascript:this.classList.add('error');this.src='https://gcore.jsdelivr.net/gh/cdn-x/placeholder@1.0.4/image/2659360.svg';"></a><a class="title" href="/"><div class="main" ff="title">愔颂</div></a></div>

<nav class="menu dis-select"><a class="nav-item active" href="/">文章</a><a class="nav-item" href="/friends/">收藏</a><a class="nav-item" href="/about/">关于</a></nav>
</header>


<div class="widgets">
<widget class="widget-wrapper search"><div class="widget-body"><div class="search-wrapper" id="search"><form class="search-form"><input type="text" class="search-input" id="search-input" data-filter="/blog/" placeholder="文章搜索"><svg t="1670596976048" class="icon search-icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2676" width="200" height="200"><path d="M938.2 832.6L723.8 618.1c-2.5-2.5-5.3-4.4-7.9-6.4 36.2-55.6 57.3-121.8 57.3-193.1C773.3 222.8 614.6 64 418.7 64S64 222.8 64 418.6c0 195.9 158.8 354.6 354.6 354.6 71.3 0 137.5-21.2 193.2-57.4 2 2.7 3.9 5.4 6.3 7.8L832.5 938c14.6 14.6 33.7 21.9 52.8 21.9 19.1 0 38.2-7.3 52.8-21.8 29.2-29.1 29.2-76.4 0.1-105.5M418.7 661.3C284.9 661.3 176 552.4 176 418.6 176 284.9 284.9 176 418.7 176c133.8 0 242.6 108.9 242.6 242.7 0 133.7-108.9 242.6-242.6 242.6" p-id="2677"></path></svg></form><div id="search-result"></div><div class="search-no-result">没有找到内容！</div></div></div></widget>


<widget class="widget-wrapper toc single" id="data-toc"><div class="widget-header cap dis-select"><span class="name">设计模式摘录</span></div><div class="widget-body fs14"><div class="doc-tree active"><ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#1%E3%80%81%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F%E6%98%AF%E4%BB%80%E4%B9%88%EF%BC%9F"><span class="toc-text">1、设计模式是什么？</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#2%E3%80%81%E5%88%9B%E5%BB%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F"><span class="toc-text">2、创建型模式</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%EF%BC%881%EF%BC%89%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95%E6%A8%A1%E5%BC%8F"><span class="toc-text">（1）工厂方法模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%EF%BC%882%EF%BC%89%E6%8A%BD%E8%B1%A1%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F"><span class="toc-text">（2）抽象工厂模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%EF%BC%883%EF%BC%89%E5%BB%BA%E9%80%A0%E8%80%85%E6%A8%A1%E5%BC%8F"><span class="toc-text">（3）建造者模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%EF%BC%884%EF%BC%89%E5%8E%9F%E5%9E%8B%E6%A8%A1%E5%BC%8F"><span class="toc-text">（4）原型模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%EF%BC%885%EF%BC%89%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F"><span class="toc-text">（5）单例模式</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#3%E3%80%81%E8%A1%8C%E4%B8%BA%E5%9E%8B%E6%A8%A1%E5%BC%8F"><span class="toc-text">3、行为型模式</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%EF%BC%881%EF%BC%89%E8%A7%82%E5%AF%9F%E8%80%85%E6%A8%A1%E5%BC%8F"><span class="toc-text">（1）观察者模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%EF%BC%882%EF%BC%89%E7%AD%96%E7%95%A5%E6%A8%A1%E5%BC%8F"><span class="toc-text">（2）策略模式</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%EF%BC%883%EF%BC%89%E6%A8%A1%E6%9D%BF%E6%96%B9%E6%B3%95%E6%A8%A1%E5%BC%8F"><span class="toc-text">（3）模板方法模式</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#4%E3%80%81%E7%BB%93%E6%9E%84%E5%9E%8B%E6%A8%A1%E5%BC%8F"><span class="toc-text">4、结构型模式</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#5%E3%80%81%E5%85%AD%E5%A4%A7%E5%8E%9F%E5%88%99"><span class="toc-text">5、六大原则</span></a></li></ol></div></div></widget>




</div>


    </aside>
    <div class='l_main'>
      

      



<div class="bread-nav fs12"><div id="breadcrumb"><a class="cap breadcrumb" href="/">主页</a><span class="sep"></span><a class="cap breadcrumb" href="/">文章</a><span class="sep"></span><a class="cap breadcrumb-link" href="/categories/%E7%B3%BB%E7%BB%9F%E8%AE%BE%E8%AE%A1/">系统设计</a></div><div id="post-meta">发布于&nbsp;<time datetime="2023-10-05T12:49:24.027Z">2023-10-05</time></div></div>

<article class='md-text content post'>
<h1 class="article-title"><span>设计模式摘录</span></h1>
<meta name="referrer" content="no-referrer"/>

<p>《深入设计模式》一书阅读摘录。</p>
<span id="more"></span>

<h2 id="1、设计模式是什么？"><a href="#1、设计模式是什么？" class="headerlink" title="1、设计模式是什么？"></a>1、设计模式是什么？</h2><p><strong>设计模式</strong>是软件设计中常见问题的典型解决方案。 它们就像能根据需求进行调整的预制蓝图， 可用于解决代码中反复出现的设计问题。</p>
<h2 id="2、创建型模式"><a href="#2、创建型模式" class="headerlink" title="2、创建型模式"></a>2、创建型模式</h2><p>创建型模式提供了创建对象的机制， 能够提升已有代码的灵活性和可复用性。</p>
<h3 id="（1）工厂方法模式"><a href="#（1）工厂方法模式" class="headerlink" title="（1）工厂方法模式"></a>（1）工厂方法模式</h3><p>工厂方法模式是一种创建型设计模式， 其在父类中提供一个创建对象的方法， 允许子类决定实例化对象的类型。</p>
<p>示例：父类提供了一个Transport接口，并提供deliver方法，子类通过继承父类实例化具体类型。</p>
<div class="tag-plugin image"><div class="image-bg"><img src="https://refactoringguru.cn/images/patterns/diagrams/factory-method/solution2-zh.png" fancybox="true"/></div></div>



<p><strong>工厂方法模式优缺点：</strong></p>
<ul>
<li><p>你可以避免创建者和具体产品之间的紧密耦合。</p>
</li>
<li><p><em>单一职责原则</em>。 你可以将产品创建代码放在程序的单一位置， 从而使得代码更容易维护。</p>
</li>
<li><p><em>开闭原则</em>。 无需更改现有客户端代码， 你就可以在程序中引入新的产品类型。</p>
</li>
<li><p>应用工厂方法模式需要引入许多新的子类， 代码可能会因此变得更复杂。 最好的情况是将该模式引入创建者类的现有层次结构中。</p>
</li>
</ul>
<h3 id="（2）抽象工厂模式"><a href="#（2）抽象工厂模式" class="headerlink" title="（2）抽象工厂模式"></a>（2）抽象工厂模式</h3><p>抽象工厂模式是一种创建型设计模式， 它能创建一系列相关的对象， 而无需指定其具体类。</p>
<p>示例：</p>
<p>1、声明<em>抽象工厂</em>——包含系列中所有产品构造方法的接口。 例如 <code>create­Chair</code>创建椅子 、  <code>create­Sofa</code>创建沙发和 <code>create­Coffee­Table</code>创建咖啡桌 。 这些方法必须返回<strong>抽象</strong>产品类型， 即我们之前抽取的那些接口：  <code>椅子</code> ，  <code>沙发</code>和 <code>咖啡桌</code>等等。</p>
<p>2、我们都将基于 <code>抽象工厂</code>接口创建不同的工厂类。 每个工厂类都只能返回特定类别的产品， 例如，  <code>现代家具工厂</code>Modern­Furniture­Factory只能创建 <code>现代椅子</code>Modern­Chair 、  <code>现代沙发</code>Modern­Sofa和 <code>现代咖啡桌</code>Modern­Coffee­Table对象。</p>
<div class="tag-plugin image"><div class="image-bg"><img src="https://refactoringguru.cn/images/patterns/diagrams/abstract-factory/solution2.png" fancybox="true"/></div></div>



<p> <strong>抽象工厂模式优缺点</strong>：</p>
<ul>
<li><p>你可以确保同一工厂生成的产品相互匹配。</p>
</li>
<li><p>你可以避免客户端和具体产品代码的耦合。</p>
</li>
<li><p><em>单一职责原则</em>。 你可以将产品生成代码抽取到同一位置， 使得代码易于维护。</p>
</li>
<li><p><em>开闭原则</em>。 向应用程序中引入新产品变体时， 你无需修改客户端代码。</p>
</li>
<li><p>由于采用该模式需要向应用中引入众多接口和类， 代码可能会比之前更加复杂。</p>
</li>
</ul>
<h3 id="（3）建造者模式"><a href="#（3）建造者模式" class="headerlink" title="（3）建造者模式"></a>（3）建造者模式</h3><p>建造者模式是一种创建型设计模式， 使你能够分步骤创建复杂对象。 该模式允许你使用相同的创建代码生成不同类型和形式的对象。</p>
<p>示例：我们想要建造不同风格的房子，如果为每种可能的房子对象都创建一个子类， 这可能会导致程序变得过于复杂。</p>
<div class="tag-plugin image"><div class="image-bg"><img src="https://refactoringguru.cn/images/patterns/diagrams/builder/problem1.png" fancybox="true"/></div></div>

<p>生成器模式建议将对象构造代码从产品类中抽取出来， 并将其放在一个名为<em>生成器</em>的独立对象中。</p>
<p>该模式会将对象构造过程划分为一组步骤， 比如 <code>build­Walls</code>创建墙壁和 <code>build­Door</code>创建房门创建房门等。 每次创建对象时， 你都需要通过生成器对象执行一系列步骤。 重点在于你无需调用所有步骤， 而只需调用创建特定对象配置所需的那些步骤即可。</p>
<div class="tag-plugin image"><div class="image-bg"><img src="https://refactoringguru.cn/images/patterns/diagrams/builder/solution1.png" fancybox="true"/></div></div>



<p><strong>生成器模式优缺点：</strong></p>
<ul>
<li><p>你可以分步创建对象， 暂缓创建步骤或递归运行创建步骤。</p>
</li>
<li><p>生成不同形式的产品时， 你可以复用相同的制造代码。</p>
</li>
<li><p><em>单一职责原则</em>。 你可以将复杂构造代码从产品的业务逻辑中分离出来。</p>
</li>
<li><p>由于该模式需要新增多个类， 因此代码整体复杂程度会有所增加。</p>
</li>
</ul>
<h3 id="（4）原型模式"><a href="#（4）原型模式" class="headerlink" title="（4）原型模式"></a>（4）原型模式</h3><p>原型模式是一种创建型设计模式， 使你能够复制已有对象， 而又无需使代码依赖它们所属的类。</p>
<p>示例：有丝分裂会产生一对完全相同的细胞。 原始细胞就是一个原型， 它在复制体的生成过程中起到了推动作用。</p>
<div class="tag-plugin image"><div class="image-bg"><img src="https://refactoringguru.cn/images/patterns/content/prototype/prototype-comic-3-zh.png" fancybox="true"/></div></div>

<p>原型模式将克隆过程委派给被克隆的实际对象。 模式为所有支持克隆的对象声明了一个通用接口， 该接口让你能够克隆对象， 同时又无需将代码和对象所属类耦合。 通常情况下， 这样的接口中仅包含一个 <code>克隆</code>方法。</p>
<p> <code>克隆</code>方法会创建一个当前类的对象， 然后将原始对象所有的成员变量值复制到新建的类中。 你甚至可以复制私有成员变量， 因为绝大部分编程语言都允许对象访问其同类对象的私有成员变量。</p>
<p>支持克隆的对象即为<em>原型</em>。</p>
<p><strong>原型模式优缺点：</strong></p>
<ul>
<li><p>你可以克隆对象， 而无需与它们所属的具体类相耦合。</p>
</li>
<li><p>你可以克隆预生成原型， 避免反复运行初始化代码。</p>
</li>
<li><p>你可以更方便地生成复杂对象。</p>
</li>
<li><p>你可以用继承以外的方式来处理复杂对象的不同配置。</p>
</li>
<li><p>克隆包含循环引用的复杂对象可能会非常麻烦。</p>
</li>
</ul>
<h3 id="（5）单例模式"><a href="#（5）单例模式" class="headerlink" title="（5）单例模式"></a>（5）单例模式</h3><p>单例模式是一种创建型设计模式， 让你能够保证一个类只有一个实例， 并提供一个访问该实例的全局节点。</p>
<ol>
<li><strong>保证一个类只有一个实例</strong>。最常见的原因是控制某些共享资源 （例如数据库或文件） 的访问权限。</li>
<li><strong>为该实例提供一个全局访问节点</strong>。</li>
</ol>
<p><strong>单例模式优缺点：</strong></p>
<ul>
<li><p>你可以保证一个类只有一个实例。</p>
</li>
<li><p>你获得了一个指向该实例的全局访问节点。</p>
</li>
<li><p>仅在首次请求单例对象时对其进行初始化。</p>
</li>
<li><p>违反了<em>单一职责原则</em>。 该模式同时解决了两个问题。</p>
</li>
<li><p>单例模式可能掩盖不良设计， 比如程序各组件之间相互了解过多等。</p>
</li>
<li><p>该模式在多线程环境下需要进行特殊处理， 避免多个线程多次创建单例对象。</p>
</li>
<li><p>单例的客户端代码单元测试可能会比较困难</p>
</li>
</ul>
<p><strong>单例模式的几种实现方式：</strong></p>
<p>1、懒汉式，线程不安全</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Singleton</span> &#123;  </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> Singleton instance;  </span><br><span class="line">    <span class="keyword">private</span> <span class="title function_">Singleton</span> <span class="params">()</span>&#123;&#125;  </span><br><span class="line">  </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Singleton <span class="title function_">getInstance</span><span class="params">()</span> &#123;  </span><br><span class="line">        <span class="keyword">if</span> (instance == <span class="literal">null</span>) &#123;  </span><br><span class="line">            instance = <span class="keyword">new</span> <span class="title class_">Singleton</span>();  </span><br><span class="line">        &#125;  </span><br><span class="line">        <span class="keyword">return</span> instance;  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p>2、懒汉式，线程安全</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Singleton</span> &#123;  </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> Singleton instance;  </span><br><span class="line">    <span class="keyword">private</span> <span class="title function_">Singleton</span> <span class="params">()</span>&#123;&#125;  </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">synchronized</span> Singleton <span class="title function_">getInstance</span><span class="params">()</span> &#123;  </span><br><span class="line">        <span class="keyword">if</span> (instance == <span class="literal">null</span>) &#123;  </span><br><span class="line">            instance = <span class="keyword">new</span> <span class="title class_">Singleton</span>();  </span><br><span class="line">        &#125;  </span><br><span class="line">        <span class="keyword">return</span> instance;  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p>3、饿汉式</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Singleton</span> &#123;  </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">static</span> <span class="type">Singleton</span> <span class="variable">instance</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Singleton</span>();  </span><br><span class="line">    <span class="keyword">private</span> <span class="title function_">Singleton</span> <span class="params">()</span>&#123;&#125;  </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Singleton <span class="title function_">getInstance</span><span class="params">()</span> &#123;  </span><br><span class="line">    <span class="keyword">return</span> instance;  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p>4、双检锁&#x2F;双重校验锁</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Singleton</span> &#123;  </span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">volatile</span> <span class="keyword">static</span> Singleton singleton;  </span><br><span class="line">    <span class="keyword">private</span> <span class="title function_">Singleton</span> <span class="params">()</span>&#123;&#125;  </span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Singleton <span class="title function_">getSingleton</span><span class="params">()</span> &#123;  </span><br><span class="line">    <span class="keyword">if</span> (singleton == <span class="literal">null</span>) &#123;  </span><br><span class="line">        <span class="keyword">synchronized</span> (Singleton.class) &#123;  </span><br><span class="line">            <span class="keyword">if</span> (singleton == <span class="literal">null</span>) &#123;  </span><br><span class="line">                singleton = <span class="keyword">new</span> <span class="title class_">Singleton</span>();  </span><br><span class="line">            &#125;  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;  </span><br><span class="line">    <span class="keyword">return</span> singleton;  </span><br><span class="line">    &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<blockquote>
<p>两次判空：</p>
<ol>
<li>如果单例已经创建了，直接调用synchronized加锁比较耗性能。所以首先判断有没有创建，没创建再加锁。</li>
<li>第二层非空检查的原因是在同时多个线程调用时，A线程获得锁并创建成功实例，之后释放锁，前面一起竞争的B线程获得锁，首先判断非空，代表已经创建了，所以不会继续去创建实例。</li>
</ol>
<p>volatile（内存可见性、禁止指令重排）：</p>
<ol>
<li>A、B两个线程创建单例，此时A已经赋值，但是没有完成变量初始化，而B线程看到instance已经赋值就拿来使用，因为instance没有完成初始化，所以使用过程中可能产生无法预料的后果。</li>
</ol>
</blockquote>
<h2 id="3、行为型模式"><a href="#3、行为型模式" class="headerlink" title="3、行为型模式"></a>3、行为型模式</h2><p>行为模式负责对象间的高效沟通和职责委派。</p>
<div class="tag-plugin image"><div class="image-bg"><img src="https://cdn.nlark.com/yuque/0/2023/png/36098302/1696572347922-e9a975ca-d125-4c53-a69a-60edb730acd4.png?x-oss-process=image%2Fresize%2Cw_1248%2Climit_0" fancybox="true"/></div></div>



<h3 id="（1）观察者模式"><a href="#（1）观察者模式" class="headerlink" title="（1）观察者模式"></a>（1）观察者模式</h3><p>观察者模式是一种行为设计模式， 允许你定义一种订阅机制， 可在对象事件发生时通知多个 “观察” 该对象的其他对象。</p>
<p>示例：如果你订阅了一份杂志或报纸， 那就不需要再去报摊查询新出版的刊物了。 出版社 （即应用中的 “发布者”） 会在刊物出版后 （甚至提前） 直接将最新一期寄送至你的邮箱中。</p>
<div class="tag-plugin image"><div class="image-bg"><img src="https://refactoringguru.cn/images/patterns/content/observer/observer-comic-2-zh.png" fancybox="true"/></div></div>



<p><strong>观察者模式优缺点：</strong></p>
<ul>
<li><p><em>开闭原则</em>。 你无需修改发布者代码就能引入新的订阅者类 （如果是发布者接口则可轻松引入发布者类）。</p>
</li>
<li><p>你可以在运行时建立对象之间的联系。</p>
</li>
<li><p>订阅者的通知顺序是随机的。</p>
</li>
</ul>
<p>示例：</p>
<p>1、创建Subject类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">import</span> java.util.ArrayList;</span><br><span class="line"><span class="keyword">import</span> java.util.List;</span><br><span class="line"> </span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Subject</span> &#123;</span><br><span class="line">   </span><br><span class="line">   <span class="keyword">private</span> List&lt;Observer&gt; observers </span><br><span class="line">      = <span class="keyword">new</span> <span class="title class_">ArrayList</span>&lt;Observer&gt;();</span><br><span class="line">   <span class="keyword">private</span> <span class="type">int</span> state;</span><br><span class="line"> </span><br><span class="line">   <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">getState</span><span class="params">()</span> &#123;</span><br><span class="line">      <span class="keyword">return</span> state;</span><br><span class="line">   &#125;</span><br><span class="line"> </span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">setState</span><span class="params">(<span class="type">int</span> state)</span> &#123;</span><br><span class="line">      <span class="built_in">this</span>.state = state;</span><br><span class="line">      notifyAllObservers();</span><br><span class="line">   &#125;</span><br><span class="line"> </span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">attach</span><span class="params">(Observer observer)</span>&#123;</span><br><span class="line">      observers.add(observer);      </span><br><span class="line">   &#125;</span><br><span class="line"> </span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">notifyAllObservers</span><span class="params">()</span>&#123;</span><br><span class="line">      <span class="keyword">for</span> (Observer observer : observers) &#123;</span><br><span class="line">         observer.update();</span><br><span class="line">      &#125;</span><br><span class="line">   &#125;  </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>2、创建Observer类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">class</span> <span class="title class_">Observer</span> &#123;</span><br><span class="line">   <span class="keyword">protected</span> Subject subject;</span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">abstract</span> <span class="keyword">void</span> <span class="title function_">update</span><span class="params">()</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>3、创建实体观察者类</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">BinaryObserver</span> <span class="keyword">extends</span> <span class="title class_">Observer</span>&#123;</span><br><span class="line"> </span><br><span class="line">   <span class="keyword">public</span> <span class="title function_">BinaryObserver</span><span class="params">(Subject subject)</span>&#123;</span><br><span class="line">      <span class="built_in">this</span>.subject = subject;</span><br><span class="line">      <span class="built_in">this</span>.subject.attach(<span class="built_in">this</span>);</span><br><span class="line">   &#125;</span><br><span class="line"> </span><br><span class="line">   <span class="meta">@Override</span></span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">void</span> <span class="title function_">update</span><span class="params">()</span> &#123;</span><br><span class="line">      System.out.println( <span class="string">&quot;Binary String: &quot;</span> </span><br><span class="line">      + Integer.toBinaryString( subject.getState() ) ); </span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>4、使用 <em>Subject</em> 和实体观察者对象。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">ObserverPatternDemo</span> &#123;</span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">      <span class="type">Subject</span> <span class="variable">subject</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Subject</span>();</span><br><span class="line"> </span><br><span class="line">      <span class="comment">//new HexaObserver(subject);</span></span><br><span class="line">      <span class="comment">//new OctalObserver(subject);</span></span><br><span class="line">      <span class="keyword">new</span> <span class="title class_">BinaryObserver</span>(subject);</span><br><span class="line"> </span><br><span class="line">      System.out.println(<span class="string">&quot;First state change: 15&quot;</span>);   </span><br><span class="line">      subject.setState(<span class="number">15</span>);</span><br><span class="line">      System.out.println(<span class="string">&quot;Second state change: 10&quot;</span>);  </span><br><span class="line">      subject.setState(<span class="number">10</span>);</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="（2）策略模式"><a href="#（2）策略模式" class="headerlink" title="（2）策略模式"></a>（2）策略模式</h3><p>在策略模式（Strategy Pattern）中一个类的行为或其算法可以在运行时更改。这种类型的设计模式属于行为型模式。</p>
<p>在策略模式定义了一系列算法或策略，并将每个算法封装在独立的类中，使得它们可以互相替换。<strong>通过使用策略模式，可以在运行时根据需要选择不同的算法，而不需要修改客户端代码。</strong></p>
<p>在策略模式中，我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。</p>
<p>示例：假如你需要前往机场。 你可以选择乘坐公共汽车、 预约出租车或骑自行车。 这些就是你的出行策略。 你可以根据预算或时间等因素来选择其中一种策略。</p>
<div class="tag-plugin image"><div class="image-bg"><img src="https://refactoringguru.cn/images/patterns/content/strategy/strategy-comic-1-zh.png" fancybox="true"/></div></div>



<p>策略模式建议找出负责用许多不同方式完成特定任务的类， 然后将其中的算法抽取到一组被称为<em>策略</em>的独立类中。</p>
<p>名为上下文的原始类必须包含一个成员变量来存储对于每种策略的引用。 上下文并不执行任务， 而是将工作委派给已连接的策略对象。</p>
<p><strong>策略模式优缺点</strong>：</p>
<ul>
<li><p>你可以在运行时切换对象内的算法。</p>
</li>
<li><p>你可以将算法的实现和使用算法的代码隔离开来。</p>
</li>
<li><p>你可以使用组合来代替继承。</p>
</li>
<li><p><em>开闭原则</em>。 你无需对上下文进行修改就能够引入新的策略。</p>
</li>
<li><p>如果你的算法极少发生改变， 那么没有任何理由引入新的类和接口。 使用该模式只会让程序过于复杂。</p>
</li>
<li><p>客户端必须知晓策略间的不同——它需要选择合适的策略。</p>
</li>
</ul>
<p>示例：</p>
<p>1、创建一个接口。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//Strategy.java</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">Strategy</span> &#123;   </span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">doOperation</span><span class="params">(<span class="type">int</span> num1, <span class="type">int</span> num2)</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>2、创建实现接口的实体类。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//OperationAdd.java</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OperationAdd</span> <span class="keyword">implements</span> <span class="title class_">Strategy</span>&#123;  </span><br><span class="line">    <span class="meta">@Override</span>   </span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">doOperation</span><span class="params">(<span class="type">int</span> num1, <span class="type">int</span> num2)</span> &#123;      </span><br><span class="line">        <span class="keyword">return</span> num1 + num2;   </span><br><span class="line">    &#125; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//OperationSubtract.java</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OperationSubtract</span> <span class="keyword">implements</span> <span class="title class_">Strategy</span>&#123;   </span><br><span class="line">    <span class="meta">@Override</span>   </span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">doOperation</span><span class="params">(<span class="type">int</span> num1, <span class="type">int</span> num2)</span> &#123;      </span><br><span class="line">        <span class="keyword">return</span> num1 - num2;   </span><br><span class="line">    &#125; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//OperationMultiply.java</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">OperationMultiply</span> <span class="keyword">implements</span> <span class="title class_">Strategy</span>&#123;  </span><br><span class="line">    <span class="meta">@Override</span>   </span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">doOperation</span><span class="params">(<span class="type">int</span> num1, <span class="type">int</span> num2)</span> &#123;      </span><br><span class="line">        <span class="keyword">return</span> num1 * num2;   </span><br><span class="line">    &#125; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>3、创建 <em>Context</em> 类。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//Context.java</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Context</span> &#123;   </span><br><span class="line">    <span class="keyword">private</span> Strategy strategy;    </span><br><span class="line">    <span class="keyword">public</span> <span class="title function_">Context</span><span class="params">(Strategy strategy)</span>&#123;      </span><br><span class="line">        <span class="built_in">this</span>.strategy = strategy;   </span><br><span class="line">    &#125;    </span><br><span class="line">    <span class="keyword">public</span> <span class="type">int</span> <span class="title function_">executeStrategy</span><span class="params">(<span class="type">int</span> num1, <span class="type">int</span> num2)</span>&#123;      </span><br><span class="line">        <span class="keyword">return</span> strategy.doOperation(num1, num2);  </span><br><span class="line">    &#125; </span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p>4、使用 <em>Context</em> 来查看当它改变策略 <em>Strategy</em> 时的行为变化。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//StrategyPatternDemo.java</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">StrategyPatternDemo</span> &#123;</span><br><span class="line">   <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title function_">main</span><span class="params">(String[] args)</span> &#123;</span><br><span class="line">      <span class="type">Context</span> <span class="variable">context</span> <span class="operator">=</span> <span class="keyword">new</span> <span class="title class_">Context</span>(<span class="keyword">new</span> <span class="title class_">OperationAdd</span>());    </span><br><span class="line">      System.out.println(<span class="string">&quot;10 + 5 = &quot;</span> + context.executeStrategy(<span class="number">10</span>, <span class="number">5</span>));</span><br><span class="line"> </span><br><span class="line">      context = <span class="keyword">new</span> <span class="title class_">Context</span>(<span class="keyword">new</span> <span class="title class_">OperationSubtract</span>());      </span><br><span class="line">      System.out.println(<span class="string">&quot;10 - 5 = &quot;</span> + context.executeStrategy(<span class="number">10</span>, <span class="number">5</span>));</span><br><span class="line"> </span><br><span class="line">      context = <span class="keyword">new</span> <span class="title class_">Context</span>(<span class="keyword">new</span> <span class="title class_">OperationMultiply</span>());    </span><br><span class="line">      System.out.println(<span class="string">&quot;10 * 5 = &quot;</span> + context.executeStrategy(<span class="number">10</span>, <span class="number">5</span>));</span><br><span class="line">   &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h3 id="（3）模板方法模式"><a href="#（3）模板方法模式" class="headerlink" title="（3）模板方法模式"></a>（3）模板方法模式</h3><p><strong>模板方法模式</strong>是一种行为设计模式， 它在超类中定义了一个算法的框架， 允许子类在不修改结构的情况下重写算法的特定步骤。</p>
<p>示例：模板方法可用于建造大量房屋。 标准房屋建造方案中可提供几个扩展点， 允许潜在房屋业主调整成品房屋的部分细节。</p>
<div class="tag-plugin image"><div class="image-bg"><img src="https://refactoringguru.cn/images/patterns/diagrams/template-method/live-example.png" fancybox="true"/></div></div>



<p>模板方法模式建议将算法分解为一系列步骤， 然后将这些步骤改写为方法， 最后在 “模板方法” 中依次调用这些方法。 步骤可以是 <code>抽象</code>的， 也可以有一些默认的实现。 为了能够使用算法， 客户端需要自行提供子类并实现所有的抽象步骤。 如有必要还需重写一些步骤 （但这一步中不包括模板方法自身）。</p>
<p><strong>模板方法模式优缺点：</strong></p>
<ul>
<li><p>你可仅允许客户端重写一个大型算法中的特定部分， 使得算法其他部分修改对其所造成的影响减小。</p>
</li>
<li><p>你可将重复代码提取到一个超类中。</p>
</li>
<li><p>部分客户端可能会受到算法框架的限制。</p>
</li>
<li><p>通过子类抑制默认步骤实现可能会导致违反<em>里氏替换原则</em>。</p>
</li>
<li><p>模板方法中的步骤越多， 其维护工作就可能会越困难。</p>
</li>
</ul>
<h2 id="4、结构型模式"><a href="#4、结构型模式" class="headerlink" title="4、结构型模式"></a>4、结构型模式</h2><p>结构型模式介绍如何将对象和类组装成较大的结构， 并同时保持结构的灵活和高效。</p>
<div class="tag-plugin image"><div class="image-bg"><img src="https://cdn.nlark.com/yuque/0/2023/png/36098302/1696508054996-bb868776-e528-402a-b19e-793a9b6f2190.png?x-oss-process=image%2Fresize%2Cw_1248%2Climit_0" fancybox="true"/></div></div>



<h2 id="5、六大原则"><a href="#5、六大原则" class="headerlink" title="5、六大原则"></a>5、六大原则</h2><p>单一职责：对象设计要求独立，不能设计万能对象。</p>
<p>开闭原则：对象修改最小化。</p>
<p>里式替换：程序扩展中抽象被具体可以替换（接口、父类、可以被实现类对象、子类替换对象）</p>
<p>迪米特：高内聚，低耦合。尽量不要依赖细节。</p>
<p>依赖倒置：面向抽象编程。也就是参数传递，或者返回值，可以使用父类类型或者接口类型。从广义上讲：基于接口编程，提前设计好接口框架。</p>
<p>接口隔离：接口设计大小要适中。过大导致污染，过小，导致调用麻烦</p>





</article>

<div class="related-wrap reveal" id="read-next"><section class="body"><div class="item" id="prev"><div class="note">较新文章</div><a href="/2023/10/06/%E9%9D%A2%E8%AF%95%E9%A2%98%E7%B2%BE%E9%80%89%EF%BC%88%E4%B8%80%EF%BC%89/">面试题精选（一）</a></div><div class="item" id="next"><div class="note">较早文章</div><a href="/2023/10/05/%E5%BE%AE%E4%BF%A1&%E6%94%AF%E4%BB%98%E5%AE%9D%E4%BB%98%E6%AC%BE%E5%AE%9E%E7%8E%B0/">微信&支付宝付款实现</a></div></section></div>






  <div class='related-wrap md-text reveal' id="comments">
    <section class='header cmt-title cap theme'>
      快来参与讨论吧
    </section>
    <section class='body cmt-body giscus'>
      

<svg class="loading" style="vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2709"><path d="M832 512c0-176-144-320-320-320V128c211.2 0 384 172.8 384 384h-64zM192 512c0 176 144 320 320 320v64C300.8 896 128 723.2 128 512h64z" p-id="2710"></path></svg>

<div id="giscus" data-repo="echoalways/giscus" data-repo-id="R_kgDOKjJRiQ" data-category="Announcements" data-category-id="DIC_kwDOKjJRic4CaUxu" data-mapping="pathname" data-strict="0" data-reactions-enabled="1" data-emit-metadata="0" data-input-position="top" data-theme="preferred_color_scheme" data-lang="zh-CN" data-loading="lazy" crossorigin="anonymous"></div>

    </section>
  </div>



      
<footer class="page-footer reveal fs12"><hr><div class="text" style="text-align:center;"><p>云无心以出岫@远岫♥</p>
<div><span id="timeDate">载入天数...</span><span id="times">载入时分秒...</span>，<span id="busuanzi_container_site_pv">总访问量: <span id="busuanzi_value_site_pv"></span>次</span>，<span id="busuanzi_container_site_uv">访客数: <span id="busuanzi_value_site_uv"></span>人</span></div></div></footer>

<script async src="//busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
<script>
  function createtime() {
    var now = new Date();
    var grt= new Date("10/03/2023 18:40:00");
    now.setTime(now.getTime()+250);
    days = (now - grt ) / 1000 / 60 / 60 / 24; dnum = Math.floor(days);
    hours = (now - grt ) / 1000 / 60 / 60 - (24 * dnum); hnum = Math.floor(hours);
    if(String(hnum).length ==1 ){hnum = "0" + hnum;} minutes = (now - grt ) / 1000 /60 - (24 * 60 * dnum) - (60 * hnum);
    mnum = Math.floor(minutes); if(String(mnum).length ==1 ){mnum = "0" + mnum;}
    seconds = (now - grt ) / 1000 - (24 * 60 * 60 * dnum) - (60 * 60 * hnum) - (60 * mnum);
    snum = Math.round(seconds); if(String(snum).length ==1 ){snum = "0" + snum;}
    document.getElementById("timeDate").innerHTML = "本站已运行 "+dnum+" 天 ";
    document.getElementById("times").innerHTML = hnum + " 小时 " + mnum + " 分 " + snum + " 秒";
  };
  setInterval("createtime()",250);
</script>

      <div class='float-panel mobile-only blur' style='display:none'>
  <button type='button' class='sidebar-toggle mobile' onclick='sidebar.toggle()'>
    <svg class="icon" style="width: 1em; height: 1em;vertical-align: middle;fill: currentColor;overflow: hidden;" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="15301"><path d="M566.407 808.3c26.9-0.1 49.3-20.8 51.6-47.6-1.9-27.7-23.9-49.7-51.6-51.6h-412.6c-28.2-1.4-52.6 19.5-55.5 47.6 2.3 26.8 24.6 47.5 51.6 47.6h416.5v4z m309.3-249.9c26.9-0.1 49.3-20.8 51.6-47.6-2.2-26.8-24.6-47.5-51.6-47.6h-721.9c-27.7-2.8-52.5 17.4-55.3 45.1-0.1 0.8-0.1 1.7-0.2 2.5 0.9 27.2 23.6 48.5 50.7 47.6H875.707z m-103.1-245.9c26.9-0.1 49.3-20.8 51.6-47.6-0.4-28.3-23.2-51.1-51.5-51.6h-618.9c-29.5-1.1-54.3 21.9-55.5 51.4v0.2c1.4 27.8 25.2 49.2 53 47.8 0.8 0 1.7-0.1 2.5-0.2h618.8z" p-id="15302"></path><path d="M566.407 808.3c26.9-0.1 49.3-20.8 51.6-47.6-1.9-27.7-23.9-49.7-51.6-51.6h-412.6c-28.2-1.4-52.6 19.5-55.5 47.6 1.9 27.7 23.9 49.7 51.6 51.6h416.5z m309.3-249.9c26.9-0.1 49.3-20.8 51.6-47.6-2.2-26.8-24.6-47.5-51.6-47.6h-721.9c-27.7-2.8-52.5 17.4-55.3 45.1-0.1 0.8-0.1 1.7-0.2 2.5 0.9 27.2 23.6 48.5 50.7 47.6H875.707z m-103.1-245.9c26.9-0.1 49.3-20.8 51.6-47.6-0.4-28.3-23.2-51.1-51.5-51.6h-618.9c-29.5-1.1-54.3 21.9-55.5 51.4v0.2c1.4 27.8 25.2 49.2 53 47.8 0.8 0 1.7-0.1 2.5-0.2h618.8z" p-id="15303"></path></svg>
  </button>
</div>

    </div>
  </div>
  <div class='scripts'>
    <script type="text/javascript">
  const stellar = {
    // 懒加载 css https://github.com/filamentgroup/loadCSS
    loadCSS: (href, before, media, attributes) => {
      var doc = window.document;
      var ss = doc.createElement("link");
      var ref;
      if (before) {
        ref = before;
      } else {
        var refs = (doc.body || doc.getElementsByTagName("head")[0]).childNodes;
        ref = refs[refs.length - 1];
      }
      var sheets = doc.styleSheets;
      if (attributes) {
        for (var attributeName in attributes) {
          if (attributes.hasOwnProperty(attributeName)) {
            ss.setAttribute(attributeName, attributes[attributeName]);
          }
        }
      }
      ss.rel = "stylesheet";
      ss.href = href;
      ss.media = "only x";
      function ready(cb) {
        if (doc.body) {
          return cb();
        }
        setTimeout(function () {
          ready(cb);
        });
      }
      ready(function () {
        ref.parentNode.insertBefore(ss, before ? ref : ref.nextSibling);
      });
      var onloadcssdefined = function (cb) {
        var resolvedHref = ss.href;
        var i = sheets.length;
        while (i--) {
          if (sheets[i].href === resolvedHref) {
            return cb();
          }
        }
        setTimeout(function () {
          onloadcssdefined(cb);
        });
      };
      function loadCB() {
        if (ss.addEventListener) {
          ss.removeEventListener("load", loadCB);
        }
        ss.media = media || "all";
      }
      if (ss.addEventListener) {
        ss.addEventListener("load", loadCB);
      }
      ss.onloadcssdefined = onloadcssdefined;
      onloadcssdefined(loadCB);
      return ss;
    },

    // 从 butterfly 和 volantis 获得灵感
    loadScript: (src, opt) => new Promise((resolve, reject) => {
      var script = document.createElement('script');
      if (src.startsWith('/')){
        src = stellar.config.root + src.substring(1);
      }
      script.src = src;
      if (opt) {
        for (let key of Object.keys(opt)) {
          script[key] = opt[key]
        }
      } else {
        // 默认异步，如果需要同步，第二个参数传入 {} 即可
        script.async = true
      }
      script.onerror = reject
      script.onload = script.onreadystatechange = function() {
        const loadState = this.readyState
        if (loadState && loadState !== 'loaded' && loadState !== 'complete') return
        script.onload = script.onreadystatechange = null
        resolve()
      }
      document.head.appendChild(script)
    }),

    // https://github.com/jerryc127/hexo-theme-butterfly
    jQuery: (fn) => {
      if (typeof jQuery === 'undefined') {
        stellar.loadScript(stellar.plugins.jQuery).then(fn)
      } else {
        fn()
      }
    }
  };
  stellar.version = '1.19.0';
  stellar.github = 'https://github.com/xaoxuu/hexo-theme-stellar/tree/1.19.0';
  stellar.config = {
    date_suffix: {
      just: '刚刚',
      min: '分钟前',
      hour: '小时前',
      day: '天前',
      month: '个月前',
    },
    root : '/',
  };

  // required plugins (only load if needs)
  stellar.plugins = {
    jQuery: 'https://gcore.jsdelivr.net/npm/jquery@3.6.2/dist/jquery.min.js'
  };

  if ('local_search') {
    stellar.search = {};
    stellar.search.service = 'local_search';
    if (stellar.search.service == 'local_search') {
      let service_obj = Object.assign({}, {"field":"all","path":"/search.json","content":true,"sort":"-date"});
      stellar.search[stellar.search.service] = service_obj;
    }
  }

  // stellar js
  stellar.plugins.stellar = Object.assign({"sites":"/js/plugins/sites.js","friends":"/js/plugins/friends.js","ghinfo":"/js/plugins/ghinfo.js","timeline":"/js/plugins/timeline.js","linkcard":"/js/plugins/linkcard.js","fcircle":"/js/plugins/fcircle.js","weibo":"/js/plugins/weibo.js"});

  stellar.plugins.marked = Object.assign("https://cdn.bootcdn.net/ajax/libs/marked/4.0.18/marked.min.js");
  // optional plugins
  if ('false' == 'true') {
    stellar.plugins.lazyload = Object.assign({"enable":false,"js":"https://gcore.jsdelivr.net/npm/vanilla-lazyload@17.8.3/dist/lazyload.min.js","transition":"blur"});
  }
  if ('true' == 'true') {
    stellar.plugins.swiper = Object.assign({"enable":true,"css":"https://unpkg.com/swiper@8.4.5/swiper-bundle.min.css","js":"https://unpkg.com/swiper@8.4.5/swiper-bundle.min.js"});
  }
  if ('' == 'true') {
    stellar.plugins.scrollreveal = Object.assign({"enable":null,"js":"https://gcore.jsdelivr.net/npm/scrollreveal@4.0.9/dist/scrollreveal.min.js","distance":"8px","duration":500,"interval":100,"scale":1});
  }
  if ('true' == 'true') {
    stellar.plugins.preload = Object.assign({"enable":true,"service":"flying_pages","instant_page":"https://gcore.jsdelivr.net/gh/volantis-x/cdn-volantis@4.1.2/js/instant_page.js","flying_pages":"https://gcore.jsdelivr.net/gh/gijo-varghese/flying-pages@2.1.2/flying-pages.min.js"});
  }
  if ('true' == 'true') {
    stellar.plugins.fancybox = Object.assign({"enable":true,"js":"https://gcore.jsdelivr.net/npm/@fancyapps/ui@4.0/dist/fancybox.umd.js","css":"https://gcore.jsdelivr.net/npm/@fancyapps/ui@4.0/dist/fancybox.css","selector":".swiper-slide img"});
  }
  if ('false' == 'true') {
    stellar.plugins.heti = Object.assign({"enable":false,"css":"https://unpkg.com/heti@0.9.2/umd/heti.min.css","js":"https://unpkg.com/heti@0.9.2/umd/heti-addon.min.js"});
  }
  if ('true' == 'true') {
    stellar.plugins.copycode = Object.assign({"enable":true,"js":"/js/plugins/copycode.js","default_text":"Copy","success_text":"Copied"});
  }
</script>

<!-- required -->

  
<script src="/js/main.js" async></script>



<!-- optional -->

  <script>
  function loadJS() {
    const els = document.querySelectorAll("#comments #giscus");
    if (els.length === 0) return;
    els.forEach((el, i) => {
      try {
        el.innerHTML = '';
      } catch (error) {
        console.log(error);
      }
      var script = document.createElement('script');
      script.src = 'https://giscus.app/client.js';
      script.async = true;
      for (let key of Object.keys(el.attributes)) {
        let attr = el.attributes[key];
        if (['class', 'id'].includes(attr.name) === false) {
          script.setAttribute(attr.name, attr.value);
        }
      }
      el.appendChild(script);
    });
  }
  window.addEventListener('DOMContentLoaded', (event) => {
    loadJS();
  });
</script>




<!-- inject -->


  </div>
</body>
</html>
